package gr.atc.epart.googlewrapper.moderator;

import gr.atc.epart.HttpConnector;
import gr.atc.epart.googlewrapper.GoogleServiceCallbackType;
import gr.atc.epart.googlewrapper.accounts.GoogleAccountCredentialStorage;
import gr.atc.epart.googlewrapper.accounts.GoogleAccountManager;
import gr.atc.epart.googlewrapper.moderator.ModeratorSubmission;
import gr.atc.epart.googlewrapper.moderator.ModeratorTopic;
import gr.atc.epart.googlewrapper.moderator.ModeratorVote.Vote;
import gr.atc.epart.googlewrapper.moderator.ModeratorVote.VoteFlag;
import gr.atc.epart.googlewrapper.youtube.YouTubeVideoEntry;

import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.gdata.client.http.GoogleGDataRequest.GoogleCookie;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Pair;

public class GoogleModerator 
{
	private final String _googleModeratorURI = "http://www.googleapis.com/moderator/v1"; 
	private Handler 				_ownerCallback;
	private String  				_authToken;
	ModeratorSeries 				_retrievingTopicsForSeries;
	ModeratorTopic					_addingSubmissionToTopic;
	
	private final int  Minus=0;
	private final int  Inappropriate=1;
	private final int  Ok=1;

	// need better handling...
	private String  _authenticatingUsername;
	private String  _authenticatingPasword;
	
	//
	// used to receive callbacks from low level asynchronous operations  
	//
	private Handler _messageHandler = new Handler() 
	{
		public void handleMessage(Message msg) 
		{
			switch(msg.what) 
			{
				case GoogleServiceCallbackType.AuthTokenReceived:

					try
					{
						String authenticationResponse = msg.getData().getString("RESPONSE");
						
						
						if (authenticationResponse.startsWith("Error=BadAuthentication"))
						{
							// bad username/password entered...retry
							_authenticatingUsername = "";
							_authenticatingPasword = "";					
							_ownerCallback.sendEmptyMessage(GoogleServiceCallbackType.UserAuthenticationRequired);
						}
						else
						{
						
							_authToken = extractAuthToken(authenticationResponse);

							// store credentials for future use
							GoogleAccountCredentialStorage credentialStorage = GoogleAccountCredentialStorage.getInstance();
							credentialStorage.setCredentials(GoogleAccountCredentialStorage.MODERATOR, _authenticatingUsername, _authenticatingPasword);
							_authenticatingUsername = "";
							_authenticatingPasword = "";					

							_ownerCallback.sendEmptyMessage(GoogleServiceCallbackType.ModeratorServiceIsReady);
						}
					}
					catch (Exception e)
					{
						sendOperationErrorMessage(e.getMessage());
					}
					
					break;

				case GoogleServiceCallbackType.UserAuthenticationRequired:
					// ok
					_ownerCallback.sendEmptyMessage(GoogleServiceCallbackType.UserAuthenticationRequired);
					break;

				case GoogleServiceCallbackType.ModeratorSeriesReceived:
	        		  //ok
	        		  String seriesFeed = msg.getData().getString("RESPONSE");

	        		  {
		        		  String error = checkResponseForError(seriesFeed);
		        		  if (error != null)
		        		  {
		        			  sendOperationErrorMessage(error);
		        			  break;
		        		  }
	        		  }
	        		  // {"error":{"errors":[{"message":"Token expired","locationType":"header","location":"Authorization"}],"code":401,"message":"Token expired"}}
	        		  
	        		  ArrayList<ModeratorSeries> seriesList = null;
	        		  
	        		  try
	        		  {
	        			  JSONObject seriesData = new JSONObject(seriesFeed);
	        			  ModeratorSeries series =	parseSeriesData(seriesData.getJSONObject("data"));
	        		  
	        			  // instead of making our object serializable, put it in an array..
	        			  // this serves our future plan to request for more than one series at a time
	        			  seriesList = new ArrayList<ModeratorSeries>();
	        			  seriesList.add(series);

	        		  }
	        		  catch (Exception e)
	        		  {
	        			// TODO Auto-generated catch block
	        			  e.printStackTrace();
	        		  }

	        		  // notify the caller that the results are ready
	        		  // and send him the series 
	        		  {
	        			  Message seriesMessage = new Message();
	        			  seriesMessage.what = GoogleServiceCallbackType.ModeratorSeriesReceived;

	        			  Bundle bundle = new Bundle();
	        			  bundle.putSerializable("SERIES", seriesList);

	        			  seriesMessage.setData(bundle);
	        			  _ownerCallback.sendMessage(seriesMessage);
	        		  }

					break;
					
				case GoogleServiceCallbackType.ModeratorSeriesTopicsReceived:
					
        		    String seriesTopicsFeed = msg.getData().getString("RESPONSE");

        		      {
		        		  String error = checkResponseForError(seriesTopicsFeed);
		        		  if (error != null)
		        		  {
		        			  sendOperationErrorMessage(error);
		        			  break;
		        		  }
	        		  }

					//
					// get the list of topics for the series
					//
        		    try
        		    {
        		    	JSONObject seriesTopics = new JSONObject(seriesTopicsFeed);
        		    	List<Integer>  topicsToRetrieve = parseSeriesTopicsList(seriesTopics.getJSONObject("data"));

        		    	// 
        		    	// Get all topics with details (counters and submissions)
        		    	// NOTE 1: this operation is not async
        		    	// NOTE 2: the original series is updated
        		    	for (int topicId :topicsToRetrieve)
        		    	{
        		    		JSONObject  topicDetails = getTopicsDetails(_retrievingTopicsForSeries.getSeriesId(),topicId);
        		    		parseTopicsDetails(_retrievingTopicsForSeries,topicDetails.getJSONObject("data"));
        		    	}
        		    	
        		    }catch (Exception e)
        		    {
        		    	e.printStackTrace();
        		    }
					
        		     // notify the caller that the results are ready
	        		 // and send him the topics 
	        		  {
	        			  Message seriesMessage = new Message();
	        			  seriesMessage.what = GoogleServiceCallbackType.ModeratorSeriesTopicsReceived;

	        			  Bundle bundle = new Bundle();
	        			  bundle.putSerializable("TOPICS", _retrievingTopicsForSeries.getTopicList() );

	        			  seriesMessage.setData(bundle);
	        			  _ownerCallback.sendMessage(seriesMessage);
	        		  }
        		    
					break;
					
				case GoogleServiceCallbackType.ModeratorSubmissionAdded:
					
        		    String submissionAddedResponse = msg.getData().getString("RESPONSE");
        		    
      		      	{
	        		  String error = checkResponseForError(submissionAddedResponse);
	        		  if (error != null)
	        		  {
	        			  sendOperationErrorMessage(error);
	        			  break;
	        		  }
      		      	}

        		    ArrayList<ModeratorSubmission> newSubmissionList = null;
        		    
        		    try
        		    {
	        			  JSONObject submissionData = new JSONObject(submissionAddedResponse);
	        			  ModeratorSubmission submission =	parseSubmissionInfo(_addingSubmissionToTopic,submissionData.getJSONObject("data"));
	        		  
	        			  // instead of making our object serializable, put it in an array..
	        			  // this serves our future plan to request for more than one series at a time
	        			  newSubmissionList = new ArrayList<ModeratorSubmission>();
	        			  newSubmissionList.add(submission);

        		    }
        		    catch (Exception e)
        		    {
        		    	
        		    }
        		    
        		    // notify the caller that the results are ready
	        		// and send him the subsmission 
	        		 {
	        			  Message submissionMessage = new Message();
	        			  submissionMessage.what = GoogleServiceCallbackType.ModeratorSubmissionAdded;

	        			  Bundle bundle = new Bundle();
	        			  bundle.putSerializable("SUBMISSION", newSubmissionList);

	        			  submissionMessage.setData(bundle);
	        			  _ownerCallback.sendMessage(submissionMessage);
	        		  }
	        		 
        		    //_ownerCallback.sendEmptyMessage(GoogleServiceCallbackType.ModeratorSubmissionAdded);
        		    
					break;

				case GoogleServiceCallbackType.ModeratorSubmissionVoteAdded:
					
					_ownerCallback.sendEmptyMessage(GoogleServiceCallbackType.ModeratorSubmissionVoteAdded);
					
					break;
					
				case GoogleServiceCallbackType.ModeratorNewSeriesAdded:
			
					  String seriesAddedResponse = msg.getData().getString("RESPONSE");
					  
	      		      {
	  	        		  String error = checkResponseForError(seriesAddedResponse);
	  	        		  if (error != null)
	  	        		  {
	  	        			  sendOperationErrorMessage(error);
	  	        			  break;
	  	        		  }
        		      }

	        		  ArrayList<ModeratorSeries> newSeriesList = null;
	        		  
	        		  try
	        		  {
	        			  JSONObject seriesData = new JSONObject(seriesAddedResponse);
	        			  ModeratorSeries series =	parseSeriesData(seriesData.getJSONObject("data"));
	        		  
	        			  // instead of making our object serializable, put it in an array..
	        			  // this serves our future plan to request for more than one series at a time
	        			  newSeriesList = new ArrayList<ModeratorSeries>();
	        			  newSeriesList.add(series);

	        		  }
	        		  catch (Exception e)
	        		  {
	        			// TODO Auto-generated catch block
	        			  e.printStackTrace();
	        		  }

	        		  // notify the caller that the results are ready
	        		  // and send him the series 
	        		  {
	        			  Message seriesMessage = new Message();
	        			  seriesMessage.what = GoogleServiceCallbackType.ModeratorNewSeriesAdded;

	        			  Bundle bundle = new Bundle();
	        			  bundle.putSerializable("SERIES", newSeriesList);

	        			  seriesMessage.setData(bundle);
	        			  _ownerCallback.sendMessage(seriesMessage);
	        		  }
        		    
					break;
					
				case GoogleServiceCallbackType.ModeratorNewTopicAdded:
					
					String topicAddedResponse = msg.getData().getString("RESPONSE");
					
					 {
	  	        		  String error = checkResponseForError(topicAddedResponse);
	  	        		  if (error != null)
	  	        		  {
	  	        			  sendOperationErrorMessage(error);
	  	        			  break;
	  	        		  }
      		         }
					 
					 ArrayList<ModeratorTopic> newTopicsList = null;
					 try
	        		  {
	        			  JSONObject topicData = new JSONObject(topicAddedResponse);
	        			  ModeratorTopic topic =	parseTopicsData(topicData.getJSONObject("data"));
	        		  
	        			  // instead of making our object serializable, put it in an array..
	        			  // this serves our future plan to request for more than one series at a time
	        			  newTopicsList = new ArrayList<ModeratorTopic>();
	        			  newTopicsList.add(topic);

	        		  }
	        		  catch (Exception e)
	        		  {
	        			  sendOperationErrorMessage(e.getMessage());
	        			  break;
	        		  }
	        		  
	        		  // notify the caller that the results are ready
	        		  // and send him the topic(s) 
	        		  {
	        			  Message newtopicsMessage = new Message();
	        			  newtopicsMessage.what = GoogleServiceCallbackType.ModeratorNewTopicAdded;

	        			  Bundle bundle = new Bundle();
	        			  bundle.putSerializable("TOPIC", newTopicsList);

	        			  newtopicsMessage.setData(bundle);
	        			  _ownerCallback.sendMessage(newtopicsMessage);
	        		  }
					
					break;
			}
		}
	
		private String checkResponseForError(String jsonString)
		{
			try
			{
				JSONObject responseString = new JSONObject(jsonString);
				
				if (responseString.has("error"))
				{
					if (responseString.getJSONObject("error").has("message"))
					{
						return responseString.getJSONObject("error").getString("message");
					}
					else if (responseString.has("errors"))
					{
						JSONArray errorsArray = responseString.getJSONArray("errors");
						JSONObject error = errorsArray.getJSONObject(0);
						if (error != null && error.has("message"))
							return error.getString("message");
					}
				}

				return null;

				// {"error":{"errors":[{"message":"Token expired","locationType":"header","location":"Authorization"}],"code":401,"message":"Token expired"}}
			} catch (JSONException e)
			{
				// TODO Auto-generated catch block
				return null;
			}
			
		}

		private void sendOperationErrorMessage(String msg)
		{
			Message errorMessage = new Message();
    		errorMessage.what = GoogleServiceCallbackType.OperationError;

    		Bundle bundle = new Bundle();
    		bundle.putString("DESCRIPTION", msg);

    		errorMessage.setData(bundle);
    		_ownerCallback.sendMessage(errorMessage);
		}
	};
	
	public GoogleModerator(Handler ownerCallback)
	{
		_ownerCallback = ownerCallback;
	}

	public void authenticate(String username,String password)
	{
		// do a test authentication
		// trying to modify the above example in order to retrieve the email from the phone
		// and the user should provide the password
		try
		 {
			// save the credentials...if the authentication is succesfull we will save them
			_authenticatingUsername = username;
			_authenticatingPasword = password;					

			
			HttpConnector connector = new HttpConnector();

			String authenticateUrl  = "https://www.google.com/accounts/ClientLogin";
				
			HashMap<String, String> parameters = new HashMap<String, String>();
			parameters.put("Email",username); 
			parameters.put("Passwd",password);
			parameters.put("source","atc-eparticipation-1.0");
			parameters.put("service","moderator");
			parameters.put("accountType","GOOGLE");	
			
			connector.executePostRequestAsync(authenticateUrl, GoogleServiceCallbackType.AuthTokenReceived, parameters, _messageHandler); 
		 }
		 catch (Exception e)
		 {
			 
		 }
	}
	
	public void authenticate()
	{
		//
		// TODO:: actually...this does not work...because the credential storage cannot create new file to store anything.
		// someone else must create the file the first time..
		//
		
		GoogleAccountCredentialStorage credentialStorage = GoogleAccountCredentialStorage.getInstance();
		Pair<String,String> credentials= credentialStorage.getCredentials(GoogleAccountCredentialStorage.MODERATOR);
		
		if (credentials == null)
		{
			// credentials for this service are not yet avaialble
			// display prompt to enter account login info
			_messageHandler.sendEmptyMessage(GoogleServiceCallbackType.UserAuthenticationRequired);
		}
		else
		{
			authenticate(credentials.first, credentials.second);
		}
	}
	
	public void getSeries(String url) throws MalformedURLException
	{
		// extract from the url the query part and request series
		retrieveSeries(extractSeriesId(url));
	}
	
	public void getSeries(int seriedId)
	{
		retrieveSeries(seriedId);
	}
	
	public void getTopics(ModeratorSeries series)
	{
		_retrievingTopicsForSeries = series;
		retrieveSeriesTopics(series.getSeriesId());
	}
	
	public void getTopicSubmissions(ModeratorTopic topic)
	{
		retrieveTopicSubmissions(topic);
	}
	
	public void addSubmision(ModeratorTopic topic,String username,String text,String location,String videoUrl)
	{
		_addingSubmissionToTopic = topic;
		addTopicSubmission(topic.getOnwerSeriesId(),topic.getId(),username,text,location,videoUrl);
	}


	public void voteSubmission(ModeratorSubmission submission,ModeratorVote vote)
	 {
		String voteString = (vote.getVote() == Vote.Plus) ? "PLUS":"MINUS";
		String flagString = (vote.getVoteFlag() == VoteFlag.Inappropriate) ? "INAPPROPRIATE" : "OK"; 
		
		addSubmissionVote(submission.getOnwerSeriesId(), submission.getId(), voteString, flagString);
	 }

	public void voteSubmission(int seriesId,int submissionId,ModeratorVote vote)
	 {
		String voteString = (vote.getVote() == Vote.Plus) ? "PLUS":"MINUS";
		String flagString = (vote.getVoteFlag() == VoteFlag.Inappropriate) ? "INAPPROPRIATE" : "OK"; 
		
		addSubmissionVote(seriesId, submissionId, voteString, flagString);
	 }

	
	public void addSeries(String name,String description,boolean videoSubmissionAllowed)
	{
		createNewSeries(name,description,videoSubmissionAllowed);
	}
	
	public void addTopic(ModeratorSeries series,String topicName,String description,String presenter)
	{
	    addNewTopicInSeries(series,topicName,description,presenter);	
	}

	public void addTopic(int seriesId,String topicName,String description,String presenter)
	{
		addNewTopicInSeries(seriesId, topicName,description, presenter);	
	}

	public String getAuthToken()
	{
		return _authToken;
	}

	public void setAuthToken(String token)
	{
		_authToken = token;
	}


	///////////////////////////////////////////////
	// implementation helpers
	/////////////////////////////////////////////////
	//
	// authentication
	//
	
	private String extractAuthToken(String authenticationResponse) throws Exception
	{
		//
		// example of an authentication response data
		//
		// SID=DQAAAIkAAABIcH-R5WoYqRnN6shpTqpsAMg8p4V-gxIptqFUGt7yVDsaGdSfR09WNdhBntZyxc6eXUIZGkR3IvstpNIVDGfA4Jv-XkEBAPuR_kFYAHvkeEMPF8qqH6n4-MfG8uss8ZACcQ0qhXcq7uTmDqKKtBwyUFNPFIFSD97f_oITUAxk8G6DURDKzpRt7jqdmKcrVvo
		// LSID=DQAAAIsAAAD3lkHvaPqNsEQEvZ-YfbksJnHsIDmeCk9SZC4-MmKFJvj87l8rKR8jIjG5KAKoeOjwb7HkheRjvVedU_Mvth4k9am2A65Z_R8VJvyKrcLoUmFK4qazVkfupR0eLsWMRlKnZ8mYYuAjlNaBe0FhPe_zqlccDhwd9A3hD9xSoJgMXYiEZr1k30XnZQ3HNNw-Lj0
		// Auth=DQAAAIsAAAAozL3z1-CBxAxmxB46lJZsci1O4gbbJEq6nEbNRKiUJPRkVubw1odQqg4e9mY0qFHlEZjAGuTsRSCfLOPdKJ2UD0vpLf_ku66I5e8y5q3xih7wEgX2UN6-5fwlpaQMcEpmqXrMehXGy4GPJTFj90rnxqItcjwCatk9Oww-PGrmVX3BEZXZ3OvB2E0iHdEUeZk

		
		String[] responseLines = authenticationResponse.split("\n");
		
		for (String line:responseLines)
		{
		    String[] data = line.split("=");
		    if (data[0].equalsIgnoreCase("Auth"))
		    	return data[1];
		}
		
		throw new Exception("Authentication error");
	}

	
	//
	// extract the series id from a google moderator url
	//
	private int extractSeriesId(String url) throws MalformedURLException
	{
		// extract from the url the ref part
		// example of a google moderator url
		// "http://www.google.com/moderator/#15/e=2233b&t=2233b.40"

		URL seriesUrl = new URL(url);
		String ref = seriesUrl.getRef().split("/")[1];
		String[] params = ref.split("&");  

		for (String param : params)  
		{  
		     String name = param.split("=")[0];  
		     String value = param.split("=")[1];  
		     // param "e" contains the series id (in hex)
		     if (name.equalsIgnoreCase("e"))
		     {
		    	return Integer.parseInt(value,16);
		     }
		}  

		return 0;
	}
	
	//
	// series 
	//
	// 
	private void retrieveSeries(int series)
	{
		/*
		try
		{
			HttpConnector connection= new HttpConnector();
	
			String getSeriesRequest  = createGetSeriesRequest(series);
			String getSeriesResponse = connection.executeGetRequest(getSeriesRequest);
			
			return new JSONObject(getSeriesResponse);
		} 
    	catch (JSONException e)
		{
			e.printStackTrace();
		}
    	
    	return null;
    	*/
		
		
		 try
		 {
			HttpConnector connector = new HttpConnector();

			String getSeriesRequest  = createGetSeriesRequest(series);
			
			//Header[] headers = new Header[1];
			//headers[0] = new BasicHeader("Authorization", "GoogleLogin auth="+_authToken);
			
			connector.executeGetRequestAsync(getSeriesRequest, GoogleServiceCallbackType.ModeratorSeriesReceived,_messageHandler);
			//connector.executeGetRequestAsync(getSeriesRequest, GoogleServiceCallbackType.ModeratorSeriesReceived,_messageHandler,headers);
		 }
		 catch (Exception e)
		 {
			 
		 }

	}

	// 
	private ModeratorSeries parseSeriesData(JSONObject seriesData) 
	{
		
		try
		{
			int seriesId = Integer.parseInt(seriesData.getJSONObject("id").getString("seriesId"));
			ModeratorSeries series = new ModeratorSeries(seriesId);
			
			series.setName(seriesData.getString("name"));
			series.setDescription(seriesData.getString("description"));
			series.setNumOfTopics(seriesData.getInt("numTopics"));
			series.setVideoSumbissionAllowed(seriesData.getBoolean("videoSubmissionAllowed"));
			
			if (seriesData.has("counters"))
			{
				JSONObject counters = seriesData.getJSONObject("counters");
				
				if (counters.has("submissions"))
					series.setNumOfSubmissions(counters.getInt("submissions"));
				
				if (counters.has("videoSubmissions"))
					series.setNumOfVideoSubmissions(counters.getInt("videoSubmissions"));
				
				if (counters.has("users"))
					series.setNumOfUsers(counters.getInt("users"));
				
				series.setcounter(ModeratorSeries.PLUS_VOTES, seriesData.getJSONObject("counters").getInt("plusVotes"));
				series.setcounter(ModeratorSeries.MINUS_VOTES, seriesData.getJSONObject("counters").getInt("minusVotes"));
				series.setcounter(ModeratorSeries.NONE_VOTES, seriesData.getJSONObject("counters").getInt("noneVotes"));
			}

			return series;
			
		} catch (NumberFormatException e)
		{
			e.printStackTrace();
		} catch (JSONException e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	private void createNewSeries(String name, String description,boolean videoSubmissionAllowed)
	{
		 try
		 {
			HttpConnector connector = new HttpConnector();
			
			String addSeriesUrl = createAddNewSeriesRequest();
			
			Header[] headers = new Header[1];
			headers[0] = new BasicHeader("Authorization", "GoogleLogin auth="+_authToken);

			JSONObject seriesData = new JSONObject();
			seriesData.put("description", description);
			seriesData.put("name", name);
			seriesData.put("videoSubmissionAllowed",videoSubmissionAllowed);

			JSONObject  seriesPostData = new JSONObject();
			seriesPostData.put("data", seriesData);
			
			StringEntity  postData = new StringEntity(seriesPostData.toString(),"UTF-8");
			postData.setContentType("application/json");				

			connector.executePostRequestAsync(addSeriesUrl, GoogleServiceCallbackType.ModeratorNewSeriesAdded, postData, _messageHandler, headers);
		 }
		 catch (Exception e)
		 {
			 
		 }

	}

	//
	// topics 
	//
	
	private void retrieveSeriesTopics(int seriesId) 
	{
		
		 try
		 {
			HttpConnector connector = new HttpConnector();
			
			String getSeriesTopicsRequest  = createGetSeriesTopicsRequest(seriesId);
			connector.executeGetRequestAsync(getSeriesTopicsRequest, GoogleServiceCallbackType.ModeratorSeriesTopicsReceived,_messageHandler);
		 }
		 catch (Exception e)
		 {
			 
		 }
		
	}

	private List<Integer> parseSeriesTopicsList(JSONObject topicsList)
	{
		List<Integer> topicsIds = new ArrayList<Integer>();
		
		try
		{
			JSONArray topicsArray = topicsList.getJSONArray("items");

			for (int i=0;i<topicsArray.length();i++)
	    	{
	    		JSONObject topicInfo = topicsArray.getJSONObject(i);
	    		
	    		int id = Integer.parseInt(topicInfo.getJSONObject("id").getString("topicId"));
	    		topicsIds.add(id);
	    	}
			
		} catch (JSONException e)
		{
			e.printStackTrace();
		}
		
		return topicsIds;
	}
		
	private JSONObject getTopicsDetails(int series,int topicId)
	{
		try
		{
			HttpConnector connection= new HttpConnector();
	
			String getTopicsDetailsRequest  = createGetTopicsDetailsRequest(series,topicId);
			String getTopicsDetailsResponse = connection.executeGetRequest(getTopicsDetailsRequest);
			
			return new JSONObject(getTopicsDetailsResponse);
		} 
    	catch (JSONException e)
		{
			e.printStackTrace();
		}
    	
    	return null;
	}
	
	private void parseTopicsDetails(ModeratorSeries seriesObject, JSONObject topicInfo)
	{
		ModeratorTopic topic = parseTopicsData(topicInfo);
		
		if (topic != null)
	    	seriesObject.addTopic(topic);
	}
	
	
	private ModeratorTopic parseTopicsData(JSONObject topicInfo)
	{
		
		try
		{
	    		int id = Integer.parseInt(topicInfo.getJSONObject("id").getString("topicId"));
	    		int ownerSeries = Integer.parseInt(topicInfo.getJSONObject("id").getString("seriesId"));
	    		
	    		ModeratorTopic topic= new ModeratorTopic(id,ownerSeries);
	    		
	    		topic.setName(topicInfo.getString("name"));
	    		topic.setDescription(topicInfo.getString("description"));
	    		topic.setPresenter(topicInfo.getString("presenter"));

	    		//TODO:: make this a class + parser (the object is optional)
	    		if (topicInfo.has("counters"))
	    		{
		    		topic.setNumOfSubmissions(topicInfo.getJSONObject("counters").getInt("submissions"));
		    		topic.setNumOfUsers(topicInfo.getJSONObject("counters").getInt("users"));
	
		    		topic.setcounter(ModeratorSeries.PLUS_VOTES, topicInfo.getJSONObject("counters").getInt("plusVotes"));
		    		topic.setcounter(ModeratorSeries.MINUS_VOTES, topicInfo.getJSONObject("counters").getInt("minusVotes"));
		    		topic.setcounter(ModeratorSeries.NONE_VOTES, topicInfo.getJSONObject("counters").getInt("noneVotes"));
	    		}
	    		
	    		//
	    		// Get the submissions for the topic (if any)
	    		//
	    		if (topic.getNumOfSubmissions()>0)
	    		{
	    			retrieveTopicSubmissions(topic);
	    		}
	    	
	    		return topic;
			
		} catch (JSONException e)
		{

			e.printStackTrace();
			return null;
		}
	}
	

	private void addNewTopicInSeries(ModeratorSeries series, String topicName,String description, String presenter)
	{
		addNewTopicInSeries(series.getSeriesId(), topicName,description, presenter);	
	}
	
	private void addNewTopicInSeries(int seriesId, String topicName,String description, String presenter)
	{
		
		 try
		 {
			HttpConnector connector = new HttpConnector();
			
			String addSeriesUrl = createAddNewTopicInSeriesRequest(seriesId);
			
			Header[] headers = new Header[1];
			headers[0] = new BasicHeader("Authorization", "GoogleLogin auth="+_authToken);

			JSONObject seriesData = new JSONObject();
			seriesData.put("name", topicName);

			if (description != null)
				seriesData.put("description", description);

			if (presenter != null)
				seriesData.put("presenter",presenter );

			JSONObject  seriesPostData = new JSONObject();
			seriesPostData.put("data", seriesData);
			
			StringEntity  postData = new StringEntity(seriesPostData.toString(),"UTF-8");
			postData.setContentType("application/json");				

			connector.executePostRequestAsync(addSeriesUrl, GoogleServiceCallbackType.ModeratorNewTopicAdded, postData, _messageHandler, headers);
		 }
		 catch (Exception e)
		 {
			 
		 }
		
	}


	//
	// submissions
	//
	
	private void retrieveTopicSubmissions(ModeratorTopic topic)
	{
		try
		{
			JSONObject  topicSubmissions = getTopicsSubmissions(topic.getOnwerSeriesId(),topic.getId());
			parseTopicSubmissions(topic,topicSubmissions.getJSONObject("data"));
		} catch (JSONException e)
		{

			e.printStackTrace();
		}
	}
	
	private void parseTopicSubmissions(ModeratorTopic topic,JSONObject topicSubmissions)
	{
		try
		{
			JSONArray submissionsArray = topicSubmissions.getJSONArray("items");

			for (int i=0;i<submissionsArray.length();i++)
	    	{
	    		JSONObject submissionInfo = submissionsArray.getJSONObject(i);
	    		
	    		topic.addSubmission(parseSubmissionInfo(topic,submissionInfo));
	    	}
			
		} catch (JSONException e)
		{

			e.printStackTrace();
		}
	}
	
	
	private ModeratorSubmission parseSubmissionInfo(ModeratorTopic topic,JSONObject submissionInfo) throws JSONException
	{
		int id = Integer.parseInt(submissionInfo.getJSONObject("id").getString("submissionId"));
		int ownerSeries = Integer.parseInt(submissionInfo.getJSONObject("id").getString("seriesId"));
		
		ModeratorSubmission submissionItem =  new ModeratorSubmission(id,topic.getId(),ownerSeries);
		
		submissionItem.setText(submissionInfo.getString("text"));

		if (submissionInfo.has("counters"))
		{
			submissionItem.setcounter(ModeratorSubmission.PLUS_VOTES, submissionInfo.getJSONObject("counters").getInt("plusVotes"));
			submissionItem.setcounter(ModeratorSubmission.MINUS_VOTES, submissionInfo.getJSONObject("counters").getInt("minusVotes"));
			submissionItem.setcounter(ModeratorSubmission.NONE_VOTES, submissionInfo.getJSONObject("counters").getInt("noneVotes"));
		}
		
		// optionally (if the series allows video attachment) we may have a video url
		if (submissionInfo.has("attachmentUrl"))
			submissionItem.setAttachementUrl(submissionInfo.getString("attachmentUrl"));
		
		if (submissionInfo.has("attribution"))
		{
			JSONObject attributionInfo = submissionInfo.getJSONObject("attribution");
			
			String name = ""; 
			if (attributionInfo.has("displayName"))
				name = attributionInfo.getString("displayName");

			String location = "";
			
			if (submissionInfo.has("geo"))
				location = submissionInfo.getJSONObject("geo").getString("location");
			else if (attributionInfo.has("location"))
				location = attributionInfo.getString("location");

			Attribution attribution = new Attribution(name,location);
			submissionItem.setAttribution(attribution);
		}
		else
		{
			// this is the case of an Anonymous submission
			String location = "";
			
			if (submissionInfo.has("geo"))
				location = submissionInfo.getJSONObject("geo").getString("location");

			Attribution attribution = new Attribution("Anonymous",location);
			submissionItem.setAttribution(attribution);
		}
		
		// the creation date is in millisecond format..
		Date creationDate = new Date(Long.parseLong(submissionInfo.getString("created")));
		submissionItem.setCreationDate(creationDate);
		
		return submissionItem;
	}
	
	private JSONObject getTopicsSubmissions(int series,int topicId)
	{
		try
		{
			HttpConnector connection= new HttpConnector();
	
			String getTopicsSubmissionsRequest  = createGetTopicSubmissionsRequest(series,topicId);
			String getTopicsSubmissionsResponse = connection.executeGetRequest(getTopicsSubmissionsRequest);
			
			return new JSONObject(getTopicsSubmissionsResponse);
		} 
    	catch (JSONException e)
		{
			e.printStackTrace();
		}
    	
    	return null;
	}

	private void addTopicSubmission(int seriesId,int topicId, String username, String text, String location, String videoUrl)
	{
	
		 try
		 {
			HttpConnector connector = new HttpConnector();
			
			String addSubmisionUrl = createAddTopicSubmissionRequest(seriesId, topicId);
	
			Header[] headers = new Header[1];
			headers[0] = new BasicHeader("Authorization", "GoogleLogin auth="+_authToken);

			
			JSONObject  attributionData = new JSONObject();
			attributionData.put("displayName", username);
			
			if (location != null)
				attributionData.put("location", location);
			
			JSONObject  submisionData = new JSONObject();
			submisionData.put("attribution", attributionData);
			submisionData.put("text", text);
			if (videoUrl != null)
				submisionData.put("attachmentUrl", videoUrl);
			
			JSONObject  submissionPostData = new JSONObject();
			submissionPostData.put("data", submisionData);
			
			StringEntity  postData = new StringEntity(submissionPostData.toString(),"UTF-8");
			postData.setContentType("application/json");				
			
			connector.executePostRequestAsync(addSubmisionUrl, GoogleServiceCallbackType.ModeratorSubmissionAdded, postData, _messageHandler, headers);
		 }
		 catch (Exception e)
		 {
			 
		 }
		
	}
		
	private void addSubmissionVote(int seriesId,int submissionId,String vote,String flag)
	{
		 try
		 {
			HttpConnector connector = new HttpConnector();
			
			String addSubmisionVoteUrl = createAddSubmissionVoteRequest(seriesId, submissionId);
			
			Header[] headers = new Header[1];
			headers[0] = new BasicHeader("Authorization", "GoogleLogin auth="+_authToken);

			JSONObject submisionData = new JSONObject();
			submisionData.put("flag", flag);
			submisionData.put("vote", vote);

			JSONObject  submissionPostData = new JSONObject();
			submissionPostData.put("data", submisionData);
			
			StringEntity  postData = new StringEntity(submissionPostData.toString(),"UTF-8");
			postData.setContentType("application/json");				

			connector.executePostRequestAsync(addSubmisionVoteUrl, GoogleServiceCallbackType.ModeratorSubmissionVoteAdded, postData, _messageHandler, headers);
		 }
		 catch (Exception e)
		 {
			 
		 }

	}
	
	//
	// 
	//
	private String createGetSeriesRequest(int seriesId)
	{
		return String.format("%s/series/%d",_googleModeratorURI,seriesId);
	}
	
	private String createGetSeriesTopicsRequest(int seriesId)
	{
		return String.format("%s/series/%d/topics",_googleModeratorURI,seriesId);
	}

	private String createGetTopicsDetailsRequest(int seriesId,int topicId)
	{
		return String.format("%s/series/%d/topics/%d",_googleModeratorURI,seriesId,topicId);
	}

	private String createGetTopicSubmissionsRequest(int seriesId,int topicId)
	{
		return String.format("%s/series/%d/topics/%d/submissions?sort=DATE_SUBMITTED_DESCENDING",_googleModeratorURI,seriesId,topicId);
	}

	private String createAddTopicSubmissionRequest(int seriesId,int topicId)
	{
		return String.format("%s/series/%d/topics/%d/submissions",_googleModeratorURI,seriesId,topicId);
	}
	
	private String createAddSubmissionVoteRequest(int seriesId,int submissionId)
	{
		return String.format("%s/series/%d/submissions/%d/votes/@me",_googleModeratorURI,seriesId,submissionId);
	}

	private String createAddNewSeriesRequest()
	{
		return String.format("%s/series",_googleModeratorURI);
	}
	
	private String createAddNewTopicInSeriesRequest(int seriesId)
	{
		return String.format("%s/series/%d/topics",_googleModeratorURI,seriesId);
	}
	
}
